package com.xhwl.logistics.strategy.impl;

import com.xhwl.logistics.bo.VehicleParkingLotSecondBO;
import com.xhwl.logistics.bo.cent.ProjectBO;
import com.xhwl.logistics.bo.cent.VehicleIntegratedConfigBO;
import com.xhwl.logistics.bo.manipulate.VehicleSyncBO;
import com.xhwl.logistics.converter.mapstruct.VehicleSyncConverter;
import com.xhwl.logistics.dto.http.CarBlackInfoKeTopDTO;
import com.xhwl.logistics.dto.http.CarBlackKeTopDTO;
import com.xhwl.logistics.dto.http.CarListInfoKeTopDTO;
import com.xhwl.logistics.dto.http.CarListKeTopDTO;
import com.xhwl.logistics.dto.http.CardRuleKeTopDTO;
import com.xhwl.logistics.dto.http.query.QueryCarBlackKeTopDTO;
import com.xhwl.logistics.dto.http.query.QueryCarListKeTopDTO;
import com.xhwl.logistics.dto.http.query.QueryCardRuleKeTopDTO;
import com.xhwl.logistics.entity.VehicleBlacklist;
import com.xhwl.logistics.entity.VehicleCar;
import com.xhwl.logistics.entity.VehicleCard;
import com.xhwl.logistics.enums.VehicleCardTypeEnum;
import com.xhwl.logistics.service.business.VehicleBlacklistBusinessService;
import com.xhwl.logistics.service.business.VehicleCarBusinessService;
import com.xhwl.logistics.service.cent.QueryProjectService;
import com.xhwl.logistics.service.impl.VehicleBlacklistServiceImpl;
import com.xhwl.logistics.service.impl.VehicleCarServiceImpl;
import com.xhwl.logistics.service.impl.VehicleCardServiceImpl;
import com.xhwl.logistics.service.impl.VehicleParkingLotServiceImpl;
import com.xhwl.logistics.service.impl.http.KeTopHttpServiceImpl;
import com.xhwl.logistics.strategy.IVehicleParkingLotSyncHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.ListUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
//@Service
public class VehicleParkingLotKeTopSyncHandlerImpl implements IVehicleParkingLotSyncHandler {

    @Autowired
    private KeTopHttpServiceImpl keTopHttpService;

    @Autowired
    private VehicleParkingLotServiceImpl vehicleParkingLotService;

    @Autowired
    private VehicleCarBusinessService vehicleCarBusinessService;

    @Autowired
    private VehicleCarServiceImpl vehicleCarService;

    @Autowired
    private VehicleBlacklistBusinessService vehicleBlacklistBusinessService;

    @Autowired
    private VehicleBlacklistServiceImpl vehicleBlacklistService;

    @Autowired
    private VehicleCardServiceImpl vehicleCardService;

    @Autowired
    private QueryProjectService queryProjectService;

    @Autowired
    private VehicleSyncConverter vehicleSyncConverter;

    @Async("threadPoolTaskExecutorForSchedule")
    @Transactional(rollbackFor = {Exception.class})
    @Override
    public void syncBlacklist(VehicleIntegratedConfigBO vehicleIntegratedConfigBO, VehicleSyncBO vehicleSyncBO) {
        log.info("KeTop sync blacklist start!");
        log.info("KeTop sync blacklist vehicleIntegratedConfigBO: " + vehicleIntegratedConfigBO);

        Integer projectId = vehicleSyncBO.getProjectId();

        QueryCarBlackKeTopDTO queryCarBlackKeTopDTO = new QueryCarBlackKeTopDTO();
        CarBlackKeTopDTO carBlackKeTopDTO = keTopHttpService.queryCarBlack(vehicleIntegratedConfigBO, queryCarBlackKeTopDTO);

        Integer pageSize = queryCarBlackKeTopDTO.getPageSize();
        Integer totalCount = carBlackKeTopDTO.getTotalCount();
        int count = totalCount / pageSize;

        List<CarBlackKeTopDTO> carBlackKeTopDTOList = new ArrayList<>();
        carBlackKeTopDTOList.add(carBlackKeTopDTO);
        for (int i = 0; i < count; i++) {
            int initPageIndex = 2;

            QueryCarBlackKeTopDTO pageQuery = new QueryCarBlackKeTopDTO();
            pageQuery.setPageIndex(initPageIndex + i);

            CarBlackKeTopDTO pageResult = keTopHttpService.queryCarBlack(vehicleIntegratedConfigBO, pageQuery);
            carBlackKeTopDTOList.add(pageResult);
        }

        List<CarBlackInfoKeTopDTO> carBlackInfoKeTopDTOList = carBlackKeTopDTOList.stream()
                .flatMap(carBlackKeTop -> carBlackKeTop.getCarBlackList().stream())
                .collect(Collectors.toList());
        List<String> plateNumberListFromVendor = carBlackInfoKeTopDTOList.stream().map(CarBlackInfoKeTopDTO::getCarNo).collect(Collectors.toList());

        List<VehicleBlacklist> vehicleBlacklistList = vehicleBlacklistService.list(vehicleBlacklistService.conditionForQueryBlacklists(projectId));
        Map<String, Integer> mapForVehicleBlacklistId = vehicleBlacklistList.stream().collect(Collectors.toMap(VehicleBlacklist::getPlateNumber, VehicleBlacklist::getId));
        List<String> plateNumberListFromCent = vehicleBlacklistList.stream().map(VehicleBlacklist::getPlateNumber).collect(Collectors.toList());

        List<String> add = ListUtils.subtract(plateNumberListFromVendor, plateNumberListFromCent);
        if (!add.isEmpty()) {
            vehicleBlacklistBusinessService.addBlacklists(add, projectId);
        }

        List<String> delete = ListUtils.subtract(plateNumberListFromCent, plateNumberListFromVendor);
        if (!delete.isEmpty()) {
            List<Integer> deleteIdList = delete.stream().map(mapForVehicleBlacklistId::get).collect(Collectors.toList());
            vehicleBlacklistService.deleteBlacklists(deleteIdList);
        }

        log.info("KeTop sync blacklist end!");
    }

    @Async("threadPoolTaskExecutorForSchedule")
    @Transactional(rollbackFor = {Exception.class})
    @Override
    public void syncCarList(VehicleIntegratedConfigBO vehicleIntegratedConfigBO, VehicleSyncBO vehicleSyncBO) {
        log.info("KeTop sync car list start!");
        log.info("KeTop sync car list vehicleIntegratedConfigBO: " + vehicleIntegratedConfigBO);

        Integer projectId = vehicleSyncBO.getProjectId();

        QueryCarListKeTopDTO queryCarListKeTopDTO = new QueryCarListKeTopDTO();
        CarListKeTopDTO carListKeTopDTO = keTopHttpService.queryCarList(vehicleIntegratedConfigBO, queryCarListKeTopDTO);

        Integer pageSize = queryCarListKeTopDTO.getPageSize();
        Integer totalCount = carListKeTopDTO.getTotalCount();
        int count = totalCount / pageSize;

        List<CarListKeTopDTO> carListKeTopDTOList = new ArrayList<>();
        carListKeTopDTOList.add(carListKeTopDTO);
        for (int i = 0; i < count; i++) {
            int initPageIndex = 2;

            QueryCarListKeTopDTO pageQuery = new QueryCarListKeTopDTO();
            pageQuery.setPageIndex(initPageIndex + i);

            CarListKeTopDTO pageResult = keTopHttpService.queryCarList(vehicleIntegratedConfigBO, pageQuery);
            carListKeTopDTOList.add(pageResult);
        }

        List<CarListInfoKeTopDTO> carListInfoKeTopDTOList = carListKeTopDTOList.stream()
                .flatMap(carListKeTop -> carListKeTop.getCarCardList().stream())
                .collect(Collectors.toList());
        Map<String, CarListInfoKeTopDTO> mapForCarListInfoKeTopDTO = carListInfoKeTopDTOList.stream()
                .collect(Collectors.toMap(carListInfoKeTopDTO -> vehicleSyncConverter.carListInfoKeTopDTO2PlateNumber(carListInfoKeTopDTO), Function.identity()));
        List<String> plateNumberListFromVendor = carListInfoKeTopDTOList.stream()
                .map(carListInfoKeTopDTO -> vehicleSyncConverter.carListInfoKeTopDTO2PlateNumber(carListInfoKeTopDTO))
                .collect(Collectors.toList());

        List<VehicleCar> vehicleCarList = vehicleCarService.list(vehicleCarService.conditionForQueryCars(projectId));
        Map<String, Integer> mapForVehicleCarId = vehicleCarList.stream().collect(Collectors.toMap(VehicleCar::getPlateNumber, VehicleCar::getId));
        List<String> plateNumberListForCent = vehicleCarList.stream().map(VehicleCar::getPlateNumber).collect(Collectors.toList());

        List<String> add = ListUtils.subtract(plateNumberListFromVendor, plateNumberListForCent);
        if (!add.isEmpty()) {
            ProjectBO projectBO = queryProjectService.queryProject(projectId);
            VehicleParkingLotSecondBO vehicleParkingLotSecondBO = vehicleParkingLotService.queryParkingLot(projectId, null);

            List<CarListInfoKeTopDTO> addForCarListInfoKeTopDTOList = add.stream().map(mapForCarListInfoKeTopDTO::get).collect(Collectors.toList());
            List<VehicleCar> addForVehicleCar = vehicleSyncConverter.toVehicleCarList(addForCarListInfoKeTopDTOList, projectId, projectBO.getProjectName(), vehicleParkingLotSecondBO.getId(), vehicleParkingLotSecondBO.getParkingLotName());
            vehicleCarService.saveBatch(addForVehicleCar);
        }

        List<String> delete = ListUtils.subtract(plateNumberListForCent, plateNumberListFromVendor);
        if (!delete.isEmpty()) {
            List<Integer> carIdList = delete.stream().map(mapForVehicleCarId::get).collect(Collectors.toList());
            vehicleCarBusinessService.deleteCars(carIdList);
        }

        log.info("KeTop sync car list end!");
    }

    @Async("threadPoolTaskExecutorForSchedule")
    @Transactional(rollbackFor = {Exception.class})
    @Override
    public void syncCardRule(VehicleIntegratedConfigBO vehicleIntegratedConfigBO, VehicleSyncBO vehicleSyncBO) {
        log.info("KeTop sync card rule start!");
        log.info("KeTop sync card rule vehicleIntegratedConfigBO: " + vehicleIntegratedConfigBO);

        Integer projectId = vehicleSyncBO.getProjectId();

        ProjectBO projectBO = queryProjectService.queryProject(projectId);
        VehicleParkingLotSecondBO vehicleParkingLotSecondBO = vehicleParkingLotService.queryParkingLot(projectId, null);

        List<VehicleCard> vehicleCardListFromVendor = Stream.of(VehicleCardTypeEnum.keTopCardType())
                .flatMap(keTopCardType -> {
                    CardRuleKeTopDTO cardRuleKeTopDTO = keTopHttpService.queryCardRule(vehicleIntegratedConfigBO, new QueryCardRuleKeTopDTO(keTopCardType));
                    return vehicleSyncConverter.toVehicleCardList(cardRuleKeTopDTO.getRuleList(), keTopCardType, projectId, projectBO.getProjectName(), vehicleParkingLotSecondBO.getId(), vehicleParkingLotSecondBO.getParkingLotName()).stream();
                })
                .sorted(Comparator.comparing(VehicleCard::getThirdRuleId))
                .collect(Collectors.toList());
        List<String> thirdRuleIdListFromVendor = vehicleCardListFromVendor.stream()
                .map(VehicleCard::getThirdRuleId)
                .collect(Collectors.toList());
        Map<String, VehicleCard> mapForVehicleCardFromVendor = vehicleCardListFromVendor.stream()
                .collect(Collectors.toMap(VehicleCard::getThirdRuleId, Function.identity()));

        List<VehicleCard> vehicleCardList = vehicleCardService.list(vehicleCardService.conditionForQueryCards(projectId));
        List<String> thirdRuleIdList = vehicleCardList.stream()
                .map(VehicleCard::getThirdRuleId)
                .collect(Collectors.toList());
        Map<String, VehicleCard> mapForVehicleCard = vehicleCardList.stream()
                .collect(Collectors.toMap(VehicleCard::getThirdRuleId, Function.identity()));

        List<String> add = ListUtils.subtract(thirdRuleIdListFromVendor, thirdRuleIdList);
        List<String> delete = ListUtils.subtract(thirdRuleIdList, thirdRuleIdListFromVendor);
        List<String> update = ListUtils.intersection(thirdRuleIdListFromVendor, thirdRuleIdList);

        if (!add.isEmpty()) {
            List<VehicleCard> addForVehicleCardList = add.stream()
                    .map(thirdRuleId -> {
                        VehicleCard vehicleCardFromVendor = mapForVehicleCardFromVendor.get(thirdRuleId);
                        Assert.notNull(vehicleCardFromVendor, "根据thirdRuleId，找不到需要新增车卡充值规则的科拓返回的信息");

                        return vehicleSyncConverter.toVehicleCard(vehicleCardFromVendor, "xxl-job");
                    })
                    .collect(Collectors.toList());

            vehicleCardService.saveBatch(addForVehicleCardList);
        }

        if (!delete.isEmpty()) {
            List<Integer> deleteForVehicleCardIdList = delete.stream()
                    .map(thirdRuleId -> {
                        VehicleCard vehicleCard = mapForVehicleCard.get(thirdRuleId);
                        Assert.notNull(vehicleCard, "根据thirdRuleId，找不到需要删除的已入库车卡充值规则");
                        return vehicleCard.getId();
                    })
                    .collect(Collectors.toList());

            vehicleCardService.deleteCards(deleteForVehicleCardIdList);
        }

        if (!update.isEmpty()) {
            List<VehicleCard> updateForVehicleCardList = update.stream()
                    .map(thirdRuleId -> {
                        VehicleCard vehicleCardFromVendor = mapForVehicleCardFromVendor.get(thirdRuleId);
                        Assert.notNull(vehicleCardFromVendor, "根据thirdRuleId，找不到需要更新的车卡充值规则的科拓返回的信息");
                        VehicleCard vehicleCard = mapForVehicleCard.get(thirdRuleId);
                        Assert.notNull(vehicleCard, "根据thirdRuleId，找不到需要更新的车卡充值规则的已入库的信息");

                        return vehicleSyncConverter.toVehicleCardForUpdate(vehicleCardFromVendor, vehicleCard.getId());
                    })
                    .collect(Collectors.toList());

            vehicleCardService.updateBatchById(updateForVehicleCardList);
        }

        log.info("KeTop sync card rule end!");
    }
}
